﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;

namespace Xml2Yaml
{
    internal class ExpatWraper : ExpatLib
    {
        private bool NoError = true;
        private Dictionary<string, string> UriMap = null;
        private YamlWriter Writer = null;

        public ExpatWraper(YamlWriter writer)
        {
            XmlParser = IntPtr.Zero;
            Writer = writer;
            UriMap = new Dictionary<string, string>();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="encoding"></param>
        public void Initialize(string encoding)
        {
            if (Writer == null)
            {
                throw new IOException("Error: did not specific output stream.");
            }

            base.InitParser(encoding);
        }

        protected override void Cleanup()
        {
            if (UriMap != null)
            {
                UriMap.Clear();
            }
            base.Cleanup();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="stream"></param>
        /// <returns></returns>
        public bool Parse(Stream stream)
        {
            const int BUFFERSIZE = 4096;

            StartDocument();

            int done = 0;

            byte[] buf = new byte[BUFFERSIZE];

            do
            {
                int count = stream.Read(buf, 0, BUFFERSIZE);
                done = count == BUFFERSIZE ? 0 : 1;
                if (XMLParse(XmlParser, buf, count, done) == XMLStatus.ERROR)
                {
                    Console.Error.WriteLine("Error!");
                    return false;
                }
            } while (done == 0);

            EndDocument();

            return NoError;
        }

        private string GetErrorMessage()
        {
            return (XmlParser == IntPtr.Zero) ? string.Empty : XMLErrorString(XMLGetErrorCode(XmlParser));
        }

        private KeyValuePair<string, string> GetNamespaceDataPair(string value)
        {
            int loc = value.IndexOf(YamlUtil.NSSep, 0); //character shouldn't be hardcoded in, NSSep

            if (loc > 0)
            {
                return new KeyValuePair<string, string>(value.Substring(0, loc), value.Substring(loc + 1));
            }
            else
            {
                return new KeyValuePair<string, string>(NaN, value);
            }
        }

        private void StartDocument()
        {
            Writer.StartDocument();
        }

        private void EndDocument()
        {
            Writer.EndDocument();
        }

        protected override void StartElement(string name, string[] atts)
        {
            KeyValuePair<string, string> pair = GetNamespaceDataPair(name);
            //ns: pair.Key, name:pair.Value

            //loop over attributes 
            IDictionary<AttributeType, string> map = new Dictionary<AttributeType, string>();
            for (int i = 0; i < atts.Length - 1; i += 2)
            {
                string attribute = atts[i];
                string value = atts[i + 1];

                KeyValuePair<string, string> dataPair = GetNamespaceDataPair(attribute);
                var attr = new AttributeType { NS = dataPair.Key, LocalName = dataPair.Value };

                map.Add(attr, value);
            }


            string ns = pair.Key == NaN ? string.Empty : pair.Key;

            Writer.WriteStartElement(ns, pair.Value, string.Empty, map);
        }

        protected override void EndElement(string name)
        {
            KeyValuePair<string, string> pair = GetNamespaceDataPair(name);
            Writer.WriteEndElement(pair.Key, pair.Value);
        }

        protected override void Characters(string data)
        {
            Writer.WriteContent(data);
        }

        protected override void Comment(string data)
        {
            Writer.WriteComment(data);
        }

        protected override void StartPrefixMapping(string prefix, string uri)
        {
            Trace.TraceInformation("[Information] StartPrefixMapping: " + prefix + " - " + uri);

            prefix = string.IsNullOrEmpty(prefix) ? NaN : prefix;
            uri = string.IsNullOrEmpty(uri) ? NaN : uri;
            if (!UriMap.ContainsKey(prefix))
            {
                UriMap.Add(prefix, uri);
            }
        }

        protected override void EndPrefixMapping(string prefix)
        {
            Trace.TraceInformation("[Information] EndPrefixMapping: " + prefix);

            prefix = string.IsNullOrEmpty(prefix) ? NaN : prefix;

            UriMap.Remove(prefix);
        }

    }
}
